package edu.java.lectures.lec05.polimorphism;

public class TestPolimorphism {

    public static void main(String[] args) {
	// System.out.println("\n\n----------EquilateralTriangle----------");
	// EquilateralTriangle rawnostranenTr = new EquilateralTriangle(3);
	// System.out.println(rawnostranenTr);
	// System.out.println(rawnostranenTr.calculatePerimeter());
	// System.out.println(rawnostranenTr.calculateSurface());
	// System.out.println(rawnostranenTr.getMedicenterName());
	//
	// System.out.println("\n\n----------IsoscelesTriangle----------");
	// IsoscelesTriangle rawnobedrenTr = new IsoscelesTriangle(2, 3);
	//
	// System.out.println(rawnobedrenTr.a);
	// System.out.println(((EquilateralTriangle)rawnobedrenTr).a);

//	 ScaleneTriangle raznostranenTr = new ScaleneTriangle(2, 4, 3);
//	 System.out.println("\n----------------------------\n");
//	 System.out.println(raznostranenTr.calculatePerimeter());
//	 raznostranenTr.executeMeIfYouCan();
	// A < B < C
	//	
	// C Cvar = Cobj;

	// UP-casting
//	 IsoscelesTriangle ravnobedrenTr = (IsoscelesTriangle)raznostranenTr;
////	 IsoscelesTriangle ravnobedrenTr = raznostranenTr;
//	 System.out.println(ravnobedrenTr.a);
//
//	 System.out.println(ravnobedrenTr.calculatePerimeter());
////	 ravnobedrenTr.executeMeIfYouCan(); // can NOT compile this line
//	 ((ScaleneTriangle)ravnobedrenTr).executeMeIfYouCan();  // OK
//	 System.out.println();
//	 System.out.println("Print1: " + raznostranenTr.a);
//	 System.out.println(((EquilateralTriangle)raznostranenTr).a);
//	 System.out.println("Print2: " + ((EquilateralTriangle)((IsoscelesTriangle)raznostranenTr)).a);
//
//	 System.out.println("Print2: " + ((EquilateralTriangle)raznostranenTr).a);
	 
	// DOWN-casting
//	 EquilateralTriangle rawnostranenTr = new EquilateralTriangle(4);
//	 System.out.println(rawnostranenTr.calculatePerimeter());
//	
//	 // explict
//	 IsoscelesTriangle raznostranenTriag = (IsoscelesTriangle)
//	 rawnostranenTr;
//	 System.out.println(raznostranenTriag.calculatePerimeter());

//	 A a = new A();
//	 C c = (C) a; // IMPOSSIBLE -> pass compilation, but fails at run-time
//	 c.executeMeIfYouCan();
//	 System.out.println(a instanceof B);

	

	C cPrim = new C();
	
//	D cPrim = new D();   // OK because D inherits C => (a instanceof C)==true
//	B cPrim= new B();   // IMPOSSIBLE -> pass compilation, but fails at run-time . Because B doesn't inherit C.
//	B cPrim =new C();  
	
//	A a = new D();
//	A a = new C();
//	A a = new B();
//	B a = cPrim;
	
	A a = cPrim; // upcasting
	// DOWNCASTING IS POSSIBLE AT RUNTIME ONLY IF IS SATISFIED:
	// (child-class-object instanceof ParentClass) == true
	// if a instanceof C => downcasting (AT RUNTIME) is possible
	//     Object 
	//      /   \ 
	//     A
	//     /
	//    B
	//    /
	//   C
	C c = (C) a; // downcasting
	c.executeMeIfYouCan();

	C cd = new D();
	B bd = cd;
	// bd instanceof D
	D d = (D) bd;
	d.executeMeIfYouCan();
	
//	//     Object 
//	//     /   \ 
//	// String  C
//	// String str = (String) cPrim; // IMPOSSIBLE (AT COMPILATION TIME)

    }

}

class A {

}

class B extends A {

}

class C extends B {
    public void executeMeIfYouCan() {
	System.out.println("blah");
    }
}

class D extends C {
    
}